package com.ruoyi.plus.config;

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import com.ruoyi.framework.util.ShiroUtils;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.schema.Column;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.util.ArrayList;
import java.util.List;


@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
@MapperScan("com.ruoyi.**.mapper*")
public class MybatisPlusConfig {

    private static final String SYSTEM_TENANT_ID = "tenant_id";

    @Value("#{'${tenant.ignoreTables}'.split(',')}")
    private List<String> ignoreTables;

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * 自动填充功能
     *
     * @return GlobalConfig
     */
    @Bean
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new MetaHandler());
        return globalConfig;
    }

    /**
     * 多租户属于 SQL 解析部分，依赖 MP 分页插件
     */
    @Bean
    @ConditionalOnProperty(prefix = "tenant", name = "enabled", havingValue = "true")
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        /*
         * 【测试多租户】 SQL 解析处理拦截器<br>
         * 这里固定写成住户 1 实际情况你可以从cookie读取，因此数据看不到 【 麻花藤 】 这条记录（ 注意观察 SQL ）<br>
         */
        List<ISqlParser> sqlParserList = new ArrayList<>();
        TenantSqlParser tenantSqlParser = new MyTenantParser();
        tenantSqlParser.setTenantHandler(new TenantHandler() {

            /**
             * 2019-8-1
             *
             * https://gitee.com/baomidou/mybatis-plus/issues/IZZ3M
             *
             * tenant_id in (1,2)
             *
             * @return Expression
             */
            @Override
            public Expression getTenantId(boolean where) {
                final boolean multipleTenantIds = false;
                if (where && multipleTenantIds) {
                    return multipleTenantIdCondition();
                } else {
                    return singleTenantIdCondition();
                }
            }

            private Expression singleTenantIdCondition() {
//                return new LongValue(1);//ID自己想办法获取到
                Long tenantId = ShiroUtils.getTenantId();
                return tenantId != null ? new LongValue(tenantId) : new LongValue(1);
            }

            private Expression multipleTenantIdCondition() {
                final InExpression inExpression = new InExpression();
                inExpression.setLeftExpression(new Column(getTenantIdColumn()));
                final ExpressionList itemsList = new ExpressionList();
                final List<Expression> inValues = new ArrayList<>(2);
//               inValues.add(new LongValue(1));//ID自己想办法获取到
//                inValues.add(new LongValue(2));
                Long tenantId = ShiroUtils.getTenantId();
                if (tenantId != null) {
                    inValues.add(new LongValue(tenantId));
                } else {
                    inValues.add(new LongValue(1));
                }
                itemsList.setExpressions(inValues);
                inExpression.setRightItemsList(itemsList);
                return inExpression;
            }

            @Override
            public String getTenantIdColumn() {
                return SYSTEM_TENANT_ID;
            }

            @Override
            public boolean doTableFilter(String tableName) {
                boolean ignore = ignoreTables.stream().anyMatch((e) -> e.trim().equalsIgnoreCase(tableName));
                return ignore || ShiroUtils.getTenantId() == null;
            }
        });

        sqlParserList.add(tenantSqlParser);
        paginationInterceptor.setSqlParserList(sqlParserList);
        return paginationInterceptor;
    }

}
